Skip to main content

第 7 章:使用 Role 封裝 playbook

什麼是 Ansible Role

前面學習了如何撰寫 Ansible playbook,並將我們的工作清單以 task 的方式在 playbook 中表列下來。然而,這樣充其量我們只能說這是一個比較方便閱讀的 Shell script 罷了。

若是今天我們清單中的任務有上百個,這樣我們的 playbook 也可能會變得非常冗長,就算語法再如何易讀,整體而言 playbook 還是會變得十分難以理解。另外,很多時候其實我們會希望有部分的部署內容是可以被其他不同的 playbook 重新使用。

為了解決上述的問題,Ansible 提供了我們在撰寫自動化腳本時一個角色 (role) 的概念。我們可以透過撰寫屬於自己的 role 來讓所有 playbook 重複使用,藉此提升透過 Ansible 自動化的靈活度

Roles

就字面上來說有角色、作用的意思,但它的全名其實是 Playbooks Roles,我們可把它當成是 Playbooks 的延伸使用。

在 Python 的世界裡,我們會把寫好的程式封裝成套件 (Packages) 並分享給他人使用,而在 Ansible 的世界裡,則是透過 Roles 做到。

  • 將 Playbook 分割成多個文件的抽象化封裝設計
  • 一鍵部署,比 Shell Script 更具結構化的腳本語言
  • 使用 YAML 格式
  • 可使用 Jinja2 (template system) 表達式,並支援變數、判斷式、迴圈…等語法

比對一下 Roles 和 Playbooks 的目錄結構,可以看到前者多了 roles/ 目錄和 chusiang.win_vim 的 role。

Playbook role
├─ LICENSE
├─ README.md
├─ ......
├─ ansible.cfg
└─ group_vars
└─ windows.yml
├─ requirements.yml
└─ roles
└─ chusiang.win_vim
├─ LICENSE
├─ README.md
├─ ......
├─ tasks
└─ templates
├─ setup.yml
├─ staging
└─ templates
└─ check_vim_version.bat.j2
playbook
├─ LICENSE
├─ README.md
├─ ......
├─ ansible.cfg
├─ defaults
└─ main.yml
├─ group_vars
└─ windows.yml
├─ setup.yml
├─ tasks
├─ main.yml
└─ use-msi.yml
└─ templates
└─ check_vim_version.bat.j2

Role 的基本結構

tree .
.
└── example_role
├── README.md # 說明文件
├── defaults
│ └── main.yml # 可被覆寫的變數。
├── files # 需複製到 Managed node 的檔案。
├── handlers
│ └── main.yml # 主要的 handler。
├── meta
│ └── main.yml
├── tasks
│ └── main.yml # 主要的 task。
├── templates # 集中存放 Jinja2 模板的目錄。
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml # 不該被覆寫的變數。

9 directories, 8 files

建立第一個 role

考量到在安裝 Docker 的過程中會需要用到 pip 這項工具,同時,這個工具很可能會在未來頻繁地被其他的 playbook 重複使用,因此,我們在這裡就來介紹如何透過 Ansible 來安裝 pip ,並將其寫成一個可以重複被利用的 role ,而非僅僅只是 playbook 中的一個 task。

在 Ubuntu 系統下,一般來說我們可以利用以下這段簡單的指令來安裝 pip:

apt-get update
apt-get install python-pip

作為我們的第一個 Ansible role,讓我們嘗試將這段指令翻譯成 Ansible 的腳本。根據官方文件,Ansible 預設會在以下路徑來尋找可執行的 roles:

  1. 與被執行 playbook 位於同一層的 roles 資料夾
  2. /etc/ansible/roles

因此,根據這樣的規則,讓我們在工作資料夾下依照以下結構新增檔案 (新增 roles/pip/main.yml):

workspace
├─ Vagrantfile
├─ inventory
├─ playbook.yml
└─ roles
└─ pip
└─ tasks
└─ main.yml

在這個結構下,pip 就是我們的第一個 role 的名稱,而這個 role 的工作流程就會被我們定義在下面的 tasks/main.yml 之中。現在打開 pip/tasks/main.yml 並在其中寫入以下內容:

main.yml
---
- name: Install pip
apt:
name: python-pip
update_cache: yes

我們在這個 role 的內容中呼叫了 Ansible 內建模組 apt,並利用它來安裝 python-pip 這個套件。其中 update_cache: yes 等效於在安裝前執行 apt-get update 這個指令。接著,打開我們的 playbook.yml,並修改為以下內容

playbook.yml
---
- hosts: server
roles:
- { role: pip, become: yes }

我們刪除了之前用來測試的 ping 的 play,並在這個 playbook 中告訴 Ansible 我們想要執行 pip 這個我們剛定義好的 role。其中要特別注意的是,become 代表我們要升高當前使用者權限 (等效於 Unix / Linux 中的 sudo 指令)來運行當前工作。

在這裡我們使用了 Ansible 最常見的方式來調用我們剛剛寫好的 role。如果有一連串的 role 要被執行,可以將其定義在 roles 這個 list 之下,比如

定義多個 role
---
- hosts: server
roles:
- { role: pip, become: yes }
- { role: curl, become: yes }
- { role: docker, become: yes }

這樣一來,Ansible 就會依序執行每一個 role。最後,重新運行我們的 playbook,並得到以下結果

運行 playbook
PLAY [server] *****************************************************************

TASK [setup] *******************************************************************
ok: [server]

TASK [pip : Install pip] ******************************************************
changed: [server]

PLAY RECAP *********************************************************************
server : ok=2 changed=1 unreachable=0 failed=0

Roles 可以降低 Playbooks 的複雜性,更可以增加 Playbooks 的可用性

怎麼使用 Roles

我們可以透過 Galaxy (銀河) 和 ansible-galaxy (Terminal) 來使用 Roles。

什麼是 Galaxy

Galaxy 的全名為 Ansible Galaxy,它是官方維護的 Roles 市集 (marketplace) 網站。我們可以在網站上取得社群成員所維護的 Roles,其 source code 存放於 GitHub。

ansible-galaxy 是什麼

ansible-galaxy 是管理 Roles 的指令,我們可以在 Terminal 裡用它搜尋 (search)、安裝 (install)、移除 (remove) Roles 等。換句話說它是 Ansible 世界的 pip

想深入了解 ansible-galaxy 的話,可以使用以下指令

man ansible-galaxy

怎麼用 Galaxy 搜尋 Roles

  1. 開啟瀏覽器 (Browsers) 並進入 https://galaxy.ansible.com

  2. 進到 Galaxy 的網站後,可在右上角的 Browser Roles 找到數不完的 Role。

  3. 在 Keyword 一欄輸入關鍵字後,接下 Enter 即可搜尋。底下將以 win_vim role 為例。

  4. 在 Details 頁籤裡,可以看到關於這個 Role 的版本記錄 (Version History)、支援的平台 (Supported Platforms) 等資訊。

    Ansible 最小支援版本 (Minimum Ansible Version) 的部份也請留意,有些語法在舊版的 Ansible 是不被支援的喔!

  5. 在 README 頁籤裡,可以看到作者寫的說明文件。一般會在 Role Variables 底下列出哪些可以被覆寫的預設變數。

怎麼用 ansible-galaxy 搜尋 Roles

除了在 Galaxy 網站搜尋 Roles 以外,我們也可以使用 ansible-galaxy search + 關鍵字進行搜尋。

怎麼安裝 Roles

請使用 ansible-galaxy install + Role 名稱 來安裝 role,如要自訂存放 Roles 的位置,請使用 -p + 路徑,詳情請參考 Download Roles | Ansible Galaxy 一文。

怎麼初始化 Roles

我們可以用 ansible-galaxy init + Role 名稱 來建立一個新 role,其檔案結構部份凍仁已在上一章的「Role 的基本結構」介紹過,這裡就不詳述了

怎麼把 Playbooks 打包成 Roles?

範例 lab/ch23/testlink 其實就是個把 Playbooks 拆開的 Role,它真正的程式進入點為 tasks/main.yml,而 setup.yml 只是為了測試 Playbooks 的正確性而存在的。這也是為什麼凍仁會用 setup.yml include tasks/main.yml,再用 tasks/main.yml include 其它 tasks 的原因。

在「19. 如何維護大型的 Playbooks?」一文時,凍仁建議大家把 Playbooks 給拆開,為的就是要把它打包成 Roles。

tree -L 2
.
├── README.md
├── Vagrantfile
├── defaults
│ └── main.yml
├── handlers
│ └── main.yml
├── requirements.yml
├── setup.yml
├── tasks
│ ├── check.yml
│ ├── main.yml
│ ├── setting_nginx.yml
│ ├── setting_php-fpm.yml
│ ├── setting_testlink.yml
│ └── setup_testlink.yml
└── templates
├── config_db.inc.php.j2
├── nginx-testlink.conf.j2
├── php7-cli.ini.j2
└── php7-fpm.ini.j2

4 directories, 16 files
  • 此例的 requirements.ymlsetup.yml 只有在作為 Playbooks 用時才會被使用。

好的 Roles 應具備什麼

  1. 在 README.md 裡提供清楚的說明文件。

  2. 在 Meta Data (meta/main.yml) 提供正確的資訊。

  3. 在 Meta Data (meta/main.yml) 寫入 Roles 的相依性 (Dependencies) 設定。

  4. 命名變數時,使用 Role 的名稱作為變數的前綴。

  5. 藉由 Travis CI 整合測試 Roles。(more)

    就上面的例子而言,我們會用 setup.yml 來進行測試。

README.md

  1. 使用 ansible-galaxy init 指令建立 Role 時會一併產生的檔案之一。
  2. 使用 Markdown 格式編寫。
  3. 內容會顯示在 README 頁面裡:在 Galaxy 上看到的樣子與 GitHub 相同。
cat README.md
Role Name
=========

A brief description of the role goes here.

Requirements
------------

Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.

Role Variables
--------------

A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the globalscope (ie. hostvars, group vars, etc.) should be mentioned here as well.

Dependencies
------------

A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.

Example Playbook
----------------

Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:

- hosts: servers
roles:
- { role: username.rolename, x: 42 }

License
-------

BSD

Author Information
------------------

An optional section for the role authors to include contact information, or a website (HTML is not allowed).

此為 ansible-galaxy init 產生的 READNE.md 範例。

Meta Data (meta/main.yml)

  1. 使用 ansible-galaxy init 指令建立 Role 時會一併產生的檔案之一。
  2. 使用 YAML 格式編寫。
  3. 內容會顯示在 Details 頁面裡面
cat meta/main.yml
galaxy_info:
author: chusiang
description: Deploy TestLink with Nginx, PHP 7 (php-fpm) and MySQL 5.6 on Ubuntu and Debian.
company: commandp Inc.
license: MIT
min_ansible_version: 2.1.2.0
platforms:
- name: Ubuntu
versions:
- trusty
- name: Debian
versions:
- jessie

galaxy_tags:
- testlink
- cms

dependencies:
- williamyeh.nginx
- chusiang.php7
- geerlingguy.mysql

此為 chusiang.testlink role 的 meta/main.yml

Dependencies

  1. 若相依於其它的 role,請於 meta/main.yml 的 dependencies 下方補上。
  2. 使用 YAML 格式編寫。
  3. 關於 Role Dependencies 可參考 Playbook Roles and Include Statements | Ansible Documentation 一文
cat meta/main.yml
...
dependencies:
- williamyeh.nginx
- chusiang.php7
- geerlingguy.mysql

此為 chusiang.testlink role 的 meta/main.yml

以上就是要上傳到 Galaxy 前該特別留意的地方,下章凍仁將講解怎麼把 Roles 上傳至 Galaxy。

怎麼在 Ansible Galaxy 分享 Roles

怎麼上傳 Roles 到 GitHub?

Galaxy 裡的 Roles 其實是存在 GitHub 上的。

  1. 在 GitHub 建立一個 Repository ,官方建議使用 ansible-role-acme 的格式進行命名。

  2. 把寫好的 Roles 加入 Git 版本控制裡。

    git commit -a
    git push
  3. 藉由 Git 從本地 (Local) 把 Roles 上傳至 GitHub

怎麼在 Galaxy 匯入 Roles

  1. 進入 Galaxy 網站,並點擊右上角的 SIGN IN
  2. 使用 GitHub OAuth 登入 Galaxy 網站
  3. 進入 My Roles 頁面,並點選左方按鈕啟用 Roles,完成後將顯示 ✔
  4. 當 Roles 太多時,可藉由右方的搜尋框進行過濾
  5. 啟用 Role 後,點擊右方的 Import Role 圖示進行匯入
  6. 匯入成功後將顯示 Succeeded,點擊,Succeeded 即可觀看這次匯入的相關資訊
    1. 我們可藉由此頁面檢查 Meta Data (meta/main.yml) 的設定是否有誤
  7. 若想自訂 Role name,可透過 Role Settings 進行更改。

以上,現在我們可以在 https://galaxy.ansible.com/chusiang/testlink/ 看到剛匯入的 Role,其中 chusiang 為 username,testlink 為 role name,而完整名稱則是 chusiang.testlink